package lifi

import (
	"log"
	"sync/atomic"
	"time"
)

type Collector interface {
	AddError(err error)
	Collect(d Data)
	WithTracking(maxTracked int) TrackingCollector
}

type TrackingCollector interface {
	Collector
	AddTrackingData(m Data) TrackingID
	AddTrackingDataList(group []Data) TrackingID
	Delivered() <-chan DeliveryInfo2
}
type collector struct {
	precision  time.Duration
	dataChain  chan<- Data
	errorChain chan error
}

func (c *collector) WithTracking(maxTracked int) TrackingCollector {
	return &trackingCollector{
		Collector: c,
		delivered: make(chan DeliveryInfo2, maxTracked),
	}
}

func (c *collector) AddError(err error) {
	//todo 处理异常数据
	//c.errorChain <- err
}

func (c *collector) Collect(d Data) {
	c.dataChain <- d
	return
}

var _ Collector = &collector{}

func NewCollector(
	dataChain chan<- Data,
) Collector {
	collect := collector{
		dataChain: dataChain,
		precision: time.Nanosecond,
	}
	return &collect
}

type TrackingID uint64

type DeliveryInfo2 interface {
	// ID is the TrackingID
	ID() TrackingID

	// Delivered returns true if the metric was processed successfully.
	Delivered() bool
}

type trackingCollector struct {
	Collector
	delivered chan DeliveryInfo2
}

func (t *trackingCollector) AddError(err error) {
	log.Printf("AddError %v", err)
	t.Collector.AddError(err)
}

func (t *trackingCollector) Collect(d Data) {
	if dd, ok := d.(*trackingData); ok {
		t.Collector.Collect(dd.Data)
		dd.d.notify()
	} else {
		t.Collector.Collect(d)
	}
}

func (t *trackingCollector) AddTrackingData(m Data) TrackingID {
	// 收集数据，并将注册Delivery处理函数（Delivery放入chan）
	dm, id := DataWithTracking(m, t.onDelivery)
	t.Collect(dm)
	return id
}

func (t *trackingCollector) AddTrackingDataList(group []Data) TrackingID {

	log.Printf("AddTrackingDataList")
	return 0
}

func (t *trackingCollector) Delivered() <-chan DeliveryInfo2 {
	return t.delivered
}

func (t *trackingCollector) onDelivery(info DeliveryInfo2) {

	select {
	case t.delivered <- info:
	default:
		log.Printf("channel is full delivery: %v", info)
	}
}

var (
	lastID uint64
)

func newTrackingID() TrackingID {
	id := atomic.AddUint64(&lastID, 1)
	return TrackingID(id)
}

type NotifyFunc = func(track DeliveryInfo2)
